//#include <stdlib.h>
//#include "utils.h" 
#include "hardware.h" 
#include "macros.h" 
#include "ex_eeprom.h" 

/* #define   OUTPUT		0 */
/* #define   INPUT		1  */

//#define   TRUE			1
//#define   FALSE 		0

//#define   ACK_OK		0
//#define   ACK_FAIL	1

#define   I2C_WRITE	0xA0
#define   I2C_READ	0xA1

#define   NEXT_BYTE	TRUE
#define   STOP			FALSE		

#define i2c_Delay() NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP()

unsigned int g_ee;

static void i2c_Write_Delay ( void )
{
	unsigned int d = 400000;
	
	while ( d-- )
	{
		NOP();
	}
}

static void i_i2c_Write_Delay ( void )
{
	unsigned int d = 200000;
	
	while ( --d )
		continue;
}

#define   TEST_ADDRESS	EX_E2_ADDR_FREE_SPACE

#if 0
void Ex_Test ( void );
void Ex_Test ( void )
{
	static unsigned short i;

	unsigned int len;

	char buf[16];

	if ( Time_10ms )
	{	
		i = RANDOM(0, 0xFFFF);
		StrCpy(buf, "Test #" );
		LongToStr(&buf[StrLen(buf)],i++);
		len = StrLen(buf);
		DBG_OUT("\nExEeprom_Test: %s", buf);
		Ex_SaveTo(TEST_ADDRESS,(unsigned char*)buf,len);
		ClearBuffer((unsigned char*)buf,16);
		Ex_LoadFrom((unsigned char*)buf, TEST_ADDRESS, len); 
		DBG_OUT("\nExEeprom_Test: %s\n", buf);
	}
}
#endif

void Ex_EEPROM_Init( void )
{
	PIN_SCL_DIR = PIN_OUTPUT;
	PIN_SDA_DIR = PIN_OUTPUT;
	PIN_SCL = 0;
	i2c_Delay();
	PIN_SDA = 0;
	i2c_Delay();
	PIN_SCL = 1;
	i2c_Delay();
	PIN_SDA = 1;
	i2c_Delay();
}


static void i2c_Stop(void)
{
	PIN_SCL = 0;
	PIN_SCL_DIR = PIN_OUTPUT;	//D
	i2c_Delay();
	
	PIN_SDA = 0;
	PIN_SDA_DIR = PIN_OUTPUT;	//D
	i2c_Delay();

	PIN_SCL = 1;
	i2c_Delay();

	PIN_SDA = 1;
	i2c_Delay();

	PIN_SCL_DIR = PIN_INPUT;	/* bus free time before next start */
	PIN_SDA_DIR = PIN_INPUT;

}

static void i2c_Restart(void)
{
	PIN_SCL_DIR = PIN_OUTPUT;	//D
	PIN_SCL = 0;                    /* ensure clock is low */
	i2c_Delay();

	PIN_SDA_DIR = PIN_OUTPUT;	//D
	PIN_SDA = 1;                     /* ensure data is high */
	i2c_Delay();
	
	PIN_SCL = 1;		/* clock pulse high */
	i2c_Delay();
	
	PIN_SDA = 0;            /* the high->low transition */
	i2c_Delay();
}

static unsigned char i2c_Get_ACK ( void )
{
	PIN_SCL = 0;
	i2c_Delay();
	
	PIN_SDA_DIR = PIN_INPUT;	
	i2c_Delay();
	
	PIN_SCL = 1;
	i2c_Delay();
	
	return PIN_SDA;
}
 
static void i2c_Send_ACK( unsigned char Status )
{
	PIN_SCL = 0;
	i2c_Delay();
	
	if ( Status ) 
	{
		PIN_SDA = 0;              /* drive line low -> more to come */
	}
	else 
	{ 
		PIN_SDA = 1;				  /* Stop transmit */
	}
	
	PIN_SDA_DIR = PIN_OUTPUT;	
	i2c_Delay();

	PIN_SCL = 1;
	i2c_Delay();

}


static void i2c_SendByte ( unsigned char Byte )
{
	unsigned char i = 8;
	
	PIN_SCL = 0;
	PIN_SCL_DIR = PIN_OUTPUT;
	i2c_Delay();

	PIN_SDA_DIR = PIN_OUTPUT;
	i2c_Delay();

	while ( i-- )
	{
		//PIN_SCL_DIR = PIN_OUTPUT;
		PIN_SCL = 0;
		i2c_Delay();
		
		if ( Byte & 0x80 )
			PIN_SDA = 1;
		else
			PIN_SDA = 0;

		Byte <<= 1;
		i2c_Delay();
		
		PIN_SCL = 1;
		//PIN_SCL_DIR = PIN_INPUT;
		i2c_Delay();
	}
 
	//PIN_SCL_DIR = PIN_OUTPUT;
}

static unsigned char i2c_ReadByte ( void )
{
	unsigned char i = 8, Byte = 0;
	
	PIN_SCL = 0;
	PIN_SCL_DIR = PIN_OUTPUT;
//	i2c_Delay();
	PIN_SDA_DIR = PIN_INPUT;
	i2c_Delay();

	while ( i-- )
	{
		PIN_SCL = 0;
		i2c_Delay();

		PIN_SCL = 1;
		i2c_Delay();
		
		Byte <<= 1;
		Byte |= PIN_SDA;
	}
	
	return Byte;
}

// HHHHHHHHHHHHHHHHHHHHHH FOR INTERRUPT HHHHHHHHHHHHHHHHHHHHHH


/* unsigned char i2c_Get_ACK ( void ) */
/* { */
/* 	PIN_SCL = 0; */
/* 	i2c_Delay(); */
	
/* 	PIN_SDA_DIR = PIN_INPUT;	 */
/* 	i2c_Delay(); */
	
/* 	PIN_SCL = 1; */
/* 	i2c_Delay(); */
	
/* 	return PIN_SDA; */
/* } */


static void i_i2c_SendByte ( unsigned char Byte )
{
	unsigned char i = 8;
	
	PIN_SCL = 0;
	PIN_SCL_DIR = PIN_OUTPUT;

	PIN_SDA_DIR = PIN_OUTPUT;
	I2_DELAY();

	while ( i-- )
	{
		//PIN_SCL_DIR = PIN_OUTPUT;
		PIN_SCL = 0;
//		I2_DELAY();

		if ( Byte & 0x80 )
			PIN_SDA = 1;
		else
			PIN_SDA = 0;

		Byte <<= 1;
//		I2_DELAY();

		PIN_SCL = 1;
		I2_DELAY();
	}
 
	//PIN_SCL_DIR = PIN_OUTPUT;
}

static unsigned char i_i2c_WriteAddress ( unsigned int Address )
{
	//i2c_Restart();
	PIN_SCL_DIR = PIN_OUTPUT;	//D
	PIN_SCL = 0;                    /* ensure clock is low */
	I2_DELAY();

	PIN_SDA_DIR = PIN_OUTPUT;	//D
	PIN_SDA = 1;                     /* ensure data is high */
	I2_DELAY();
	
	PIN_SCL = 1;		/* clock pulse high */
	I2_DELAY();

	PIN_SDA = 0;            /* the high->low transition */
	I2_DELAY();
	I2_DELAY();
	/*  */



	i_i2c_SendByte ( I2C_WRITE );  						/* Control byte - Write Mode */
	
	I2C_GET_ACK();
	if ( PIN_SDA == ACK_FAIL )
		return FALSE;

	i_i2c_SendByte ( (unsigned char)(Address>>8) );  /* Address - High Byte */
	I2C_GET_ACK();
	if ( PIN_SDA == ACK_FAIL )
		return FALSE;

	i_i2c_SendByte ( (unsigned char)Address );  						/* Address - Low Byte */
	I2C_GET_ACK();
	if ( PIN_SDA == ACK_FAIL )
		return FALSE;

	return TRUE;
}

static unsigned char i2c_WriteAddress ( unsigned int Address )
{
	i2c_Restart();

	i2c_SendByte ( I2C_WRITE );  						/* Control byte - Write Mode */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return FALSE;

	i2c_SendByte ( (unsigned char)(Address>>8) );  /* Address - High Byte */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return FALSE;

	i2c_SendByte ( (unsigned char)Address );  						/* Address - Low Byte */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return FALSE;

	return TRUE;
}
 
unsigned char Ex_WriteByte( unsigned int Address, unsigned char Byte )
{
	if ( i2c_WriteAddress( Address ) == FALSE )
		return FALSE;
	
	i2c_SendByte ( Byte );  
	if ( i2c_Get_ACK() == ACK_FAIL )
		return FALSE;

	i2c_Stop();
	i2c_Write_Delay();

	return TRUE;
}
 
int Ex_ReadByte ( unsigned int Address )
{
	unsigned char Byte = 0;
	
	if ( i2c_WriteAddress( Address ) == FALSE )
		return I2C_ERROR;

	i2c_Restart();					  /* Address write complete */

	i2c_SendByte ( I2C_READ );  /* Send Control Byte for read */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return I2C_ERROR;

	Byte = i2c_ReadByte();
	i2c_Send_ACK( STOP );	

	return Byte;
}


int Ex_StrCmp( register const unsigned char* Reference, unsigned int Address  )
{
	register signed int Result;

	g_ee = 0;
	

	while( !(Result = (unsigned char)*Reference - (unsigned char)Ex_ReadByte(Address++) ) && *Reference++ )
	{
		g_ee++;
	}

	return Result;
}

 
unsigned char Ex_ClearAll( void )
{
	unsigned int Address = 0;
	unsigned char i;  
	
	do
	{
		if ( i2c_WriteAddress( Address ) == FALSE )
			return FALSE;

		for ( i = 0; i < 128; i++ ) /* Write page; 128 bytes - EEPROM buffer size */
		{
			i2c_SendByte ( 0xFF );  
			if ( i2c_Get_ACK() == ACK_FAIL )
				return FALSE;
		}

		Address += 128;			  /* next page */

		i2c_Stop();

		i2c_Write_Delay();
		
	}
	while ( Address & 0xFFFF);

	return TRUE;
}

int Ex_CheckRecord(  unsigned int RecordAddress, void* Reference, unsigned int ByteCount )
{
	unsigned char *ref = (unsigned char*)Reference;

	if ( i2c_WriteAddress( RecordAddress ) == FALSE )
		return -1;

	i2c_Restart();					  /* Address write complete */
	
	i2c_SendByte ( I2C_READ );  /* Send Control Byte for read */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return -1;

	int bc = 0;

	while ( ByteCount-- )
	{
		if ( *ref++ != i2c_ReadByte() )
			break;
					  
		if ( ByteCount )
			i2c_Send_ACK( NEXT_BYTE );
		else
			i2c_Send_ACK( STOP );
		
		bc++;
	}

	return bc;
}
 
int Ex_ReadData( unsigned int Address, void* Buffer, unsigned int ByteCount )
{
	unsigned char *buf = (unsigned char*)Buffer;

	if ( i2c_WriteAddress( Address ) == FALSE )
		return -1;

	i2c_Restart();					  /* Address write complete */
	
	i2c_SendByte ( I2C_READ );  /* Send Control Byte for read */
	if ( i2c_Get_ACK() == ACK_FAIL )
		return -1;

	unsigned int bc = 0; 
	
	while ( ByteCount-- )
	{
		*buf++ = i2c_ReadByte();
		
		if ( ByteCount )
			i2c_Send_ACK( NEXT_BYTE );
		else
			i2c_Send_ACK( STOP );
		
		bc++;
	}

	return bc;
}


unsigned char i_Ex_SaveTo( unsigned int Address, unsigned char* Buffer, unsigned char ByteCount )
{

 WA:
	if ( i_i2c_WriteAddress( Address ) == FALSE )
		return 1;

	while ( 1)   
	{
		i_i2c_SendByte ( *Buffer++ );  
		I2C_GET_ACK();
		if ( PIN_SDA == ACK_FAIL )
			return 2;
		
		if ( --ByteCount == 0 )
			break;
	
		if ( (++Address & 0x7F) == 0 )
			break;

	}
	
//	i2c_Stop();
	PIN_SCL = 0;
	PIN_SCL_DIR = PIN_OUTPUT;	//D
	I2_DELAY();
	
	PIN_SDA = 0;
	PIN_SDA_DIR = PIN_OUTPUT;	//D
	I2_DELAY();

	PIN_SCL = 1;
	I2_DELAY();

	PIN_SDA = 1;
	I2_DELAY();

	PIN_SCL_DIR = PIN_INPUT;	/* bus free time before next start */
	PIN_SDA_DIR = PIN_INPUT;


	i_i2c_Write_Delay();
	
	if ( ByteCount != 0 )
	{
		goto WA;
	}

	return 0;
}

//unsigned char Ex_SaveTo( unsigned int Address, unsigned char* Buffer, unsigned int ByteCount )
int Ex_WriteData( unsigned int Address, void* Buffer, unsigned int ByteCount )
{
	unsigned char *buf = (unsigned char*)Buffer;
	unsigned int bc = ByteCount;
	unsigned int addr = Address;
	
 WA:
	if ( i2c_WriteAddress( addr ) == FALSE )
		return FALSE;

	while ( 1)   
	{
		i2c_SendByte ( *buf++ );  
		if ( i2c_Get_ACK() == ACK_FAIL )
			return FALSE;
		
		if ( --bc == 0 )
			break;
	
		if ( (++addr & 0x7F) == 0 )
			break;

	}
	
	i2c_Stop();

	i2c_Write_Delay();
	
	if ( bc != 0 )
	{
		goto WA;
	}

		 
	return Ex_CheckRecord( Address, Buffer, ByteCount );
}

/* return 0 if all mem was set  */
int Ex_MemSet( unsigned int Address, unsigned char Fill, unsigned int ByteCount )
{

 WA:
	if ( i2c_WriteAddress( Address ) == FALSE )
		return FALSE;

	while ( 1)
	{
		i2c_SendByte ( Fill );  
		if ( i2c_Get_ACK() == ACK_FAIL )
			return FALSE;
		
		if ( --ByteCount == 0 )
			break;
	
		if ( (++Address & 0x7F) == 0 )
			break;
	}
	
	i2c_Stop();

	i2c_Write_Delay();
	
	if ( ByteCount != 0 )
	{
		goto WA;
	}

	return ByteCount;
}


/* unsigned char Ex_SaveAndCheck( unsigned int Address, unsigned char* Buffer, unsigned char ByteCount ) */
/* { */
	
/* 	if ( Ex_SaveTo( Address, Buffer, ByteCount ) == FALSE ) */
/* 		return FALSE; */

/* 	if ( Ex_CheckRecord( Buffer, Address, ByteCount ) == FALSE ) */
/* 		return FALSE; */

/* 	return TRUE; */
/* } */


